#include "cv_canvas.hpp"

cvCanvas::cvCanvas(cvCanvasParam &param) : mParam(param)
{
    //
    // mWidth = mParam.width / mParam.resolution;
    // mHeight = mParam.height / mParam.resolution;
    // bg = cv::Mat(mWidth, mHeight, CV_8UC3, cv::Scalar(255, 255, 255)).clone();
    // DrawGrid();
    Reset_();
}

void cvCanvas::Reset()
{
    Reset_();
}
void cvCanvas::Reset_()
{
    mWidth  = mParam.width / mParam.resolution;
    mHeight = mParam.height / mParam.resolution;
    bg      = cv::Mat(mWidth, mHeight, CV_8UC3, cv::Scalar(255, 255, 255)).clone();
    DrawGrid();
}

cvCanvas::cvCanvas()
{
    //
    // cvCanvasParam param;
    // mParam
    // mParam.resolution = 0.01f;
    // mParam.minx = -10.f;
    // mParam.miny = -10.f;
    // mParam.width = 20.f;  // 2000 * 0.01f;
    // mParam.height = 20.f; // 2000 * 0.01f;
    // mParam.grid_width = 0.5f;
    //
    // mWidth = mParam.width / mParam.resolution;
    // mHeight = mParam.height / mParam.resolution;
    // bg = cv::Mat(mWidth, mHeight, CV_8UC3, cv::Scalar(255, 255, 255)).clone();
    // DrawGrid();
    Reset_();
}

cv::Point2i cvCanvas::realToIndex(float x, float y)
{
    cv::Point2i output;
    output.x = (x - mParam.minx) / mParam.resolution;
    output.x = output.x < mWidth - 1 ? output.x : mWidth - 1;
    int y_tmp = (y - mParam.miny) / mParam.resolution;
    y_tmp = y_tmp < mHeight - 1 ? y_tmp : mHeight - 1;
    output.y = mHeight - 1 - y_tmp;
    return output;
};
int cvCanvas::x2index(float x)
{
    cv::Point2i output;
    output.x = (x - mParam.minx) / mParam.resolution;
    output.x = output.x < mWidth - 1 ? output.x : mWidth - 1;
    return output.x;
}
int cvCanvas::y2index(float y)
{
    cv::Point2i output;
    int y_tmp = (y - mParam.miny) / mParam.resolution;
    y_tmp = y_tmp < mHeight - 1 ? y_tmp : mHeight - 1;
    output.y = mHeight - 1 - y_tmp;
    return output.y;
}

void cvCanvas::DrawGrid()
{
    //
    cv::Point2i zero_index = realToIndex(0, 0);
    //
    int x_tick_min = 0;
    int x_tick_max = 0;
    int y_tick_min = 0;
    int y_tick_max = 0;
    //
    std::vector<int> x_grid_index_list;
    x_grid_index_list.push_back(zero_index.x);
    // add x grid index
    for (float x = mParam.grid_width; xInRange(x); x += mParam.grid_width)
    {
        x_grid_index_list.push_back(x2index(x));
        x_tick_max++;
    }
    for (float x = -mParam.grid_width; xInRange(x); x -= mParam.grid_width)
    {
        x_grid_index_list.push_back(x2index(x));
        x_tick_min--;
    }
    //
    std::vector<int> y_grid_index_list;
    y_grid_index_list.push_back(zero_index.y);
    for (float y = mParam.grid_width; yInRange(y); y += mParam.grid_width)
    {
        y_grid_index_list.push_back(y2index(y));
        y_tick_max++;
    }
    for (float y = -mParam.grid_width; yInRange(y); y -= mParam.grid_width)
    {
        y_grid_index_list.push_back(y2index(y));
        y_tick_min--;
    }
    // draw grid lines
    for (auto item : x_grid_index_list)
    {
        cv::line(bg, cv::Point2i(item, 0), cv::Point2i(item, mHeight - 1),
                 cv::Scalar(222, 222, 222),
                 1);
        if (item == zero_index.x)
        {
            cv::line(bg, cv::Point2i(item, 0), cv::Point2i(item, mHeight - 1),
                     cv::Scalar(0, 222, 0),
                     2);
        }
    }
    for (auto item : y_grid_index_list)
    {
        cv::line(bg, cv::Point2i(0, item), cv::Point2i(mWidth - 1, item),
                 cv::Scalar(222, 222, 222),
                 1);
        if (item == zero_index.y)
        {
            cv::line(bg, cv::Point2i(0, item), cv::Point2i(mWidth - 1, item),
                     cv::Scalar(0, 0, 222),
                     2);
        }
    }
    // draw text tick
    for (int i = x_tick_min; i <= x_tick_max; i++)
    {
        char s[100];
        sprintf(s, "%.1f", i * mParam.grid_width);
        cv::putText(bg, std::string(s), cv::Point2i(x2index(i * mParam.grid_width) - 10, zero_index.y + 20), cv::FONT_HERSHEY_SCRIPT_SIMPLEX, 0.5, cv::Scalar(234, 34, 234), 1, 8, 0);
    }
    for (int i = y_tick_min; i <= y_tick_max; i++)
    {
        char s[100];
        sprintf(s, "%.1f", i * mParam.grid_width);
        cv::putText(bg, std::string(s), cv::Point2i(zero_index.x, y2index(i * mParam.grid_width)), cv::FONT_HERSHEY_SCRIPT_SIMPLEX, 0.5, cv::Scalar(234, 34, 234), 1, 8, 0);
    }
}
